﻿namespace PugLib.Filters
{
	using System;
	using System.Collections.Generic;
	using System.Linq;
	using System.Linq.Expressions;
	using System.Diagnostics;

	public static class SearchFilterQuery
	{
		public static IList<T> Execute<T>(IEnumerable<T> items, SearchFilterGroup group)
		{
			return Execute(items, group.Filters, group.MatchType, true);
		}

		public static IList<T> Execute<T>(IEnumerable<T> items, List<SearchFilter> filters, MatchStyle match, bool executeInParallel)
		{
			IList<T> list = new List<T>(items);

			if (MatchStyle.All == match)
			{
				if (executeInParallel)
				{
					TestTimer timerB = new TestTimer("PLINQ", true);
					foreach (SearchFilter filter in filters)
					{
						if (list.Count == 0)
						{
							Debug.WriteLine("broke out of loop");
							break;
						}
						list = list.Where(FunctionFactory.MakeFunction(list[0], filter)).AsParallel().ToList();
					}
					timerB.StopAndOutput(Console.WriteLine);
				}
				else
				{
					TestTimer timerA = new TestTimer("LINQ", true);
					foreach (SearchFilter filter in filters)
					{
						if (list.Count == 0)
						{
							Console.WriteLine("broke out of loop");
							break;
						}
						list = list.Where(FunctionFactory.MakeFunction(list[0], filter)).ToList();
					}
					timerA.StopAndOutput(Console.WriteLine);
				}
			}
			else if (MatchStyle.Any == match)
			{
				if (filters.Count == 0)
				{
					return list;
				}

				Expression<Func<T, bool>> predicate = PredicateBuilder.False<T>(); // default to none
				foreach (SearchFilter filter in filters)
				{
					predicate = predicate.Or<T>(FunctionFactory.MakeExpression(list[0], filter));
				}
				list = list.Where(predicate.Compile()).ToList();
			}
			return list;
		}
	}
}